home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / graphics / texdraw / texdraw.tex < prev    next >
Text File  |  1992-07-06  |  49KB  |  1,123 lines

  1. % TeXdraw macros
  2.  
  3. % $Id: texdraw.tex,v 1.15 1992/07/07 14:46:28 kabal Rel $
  4.  
  5. %   Copyright (C) 1991, 1992  Peter Kabal
  6.  
  7. % The TeXdraw routines in this file are provided free of charge without
  8. % warranty of any kind.  Note that the TeXdraw routines are copyrighted.
  9. % They may be distributed freely provided that the recipients also
  10. % acquire the right to distribute them freely.  The notices to this
  11. % effect must be preserved when the files are distributed.
  12.  
  13. %  Peter Kabal
  14. %  Department of Electrical Engineering
  15. %  McGill University
  16. %  3480 University
  17. %  Montreal, Quebec
  18. %  Canada  H3A 2A7
  19.  
  20. %  kabal@aldebaran.EE.McGill.CA
  21.  
  22. \def\setRevDate $#1 #2 #3${\def\TeXdrawId{TeXdraw V1R4a <#2>}}
  23. \setRevDate $Date: 1992/07/07 14:46:28 $
  24.  
  25. % ===============================================================
  26.  
  27. % The TeXdraw macros allow PostScript line drawings and such to be
  28. % generated from within TeX.
  29. % (1) TeXdraw allows TeX text (either horizontal or rotated) to be
  30. %     superimposed on the figure.
  31. % (2) TeXdraw implements a \bsegment-\dsegment environment which allows
  32. %     parameter changes and coordinate changes to be kept local.  In
  33. %     effect, these segments are self-contained relocatable procedures.
  34. % (3) TeX's macro facility can be used to advantage to modularize drawing
  35. %     units and produce more complex entities from simple elements.
  36. % (4) The drawing can be positioned on the page like any other TeX box.
  37.  
  38. % TeXdraw coordinate units have positive X to the right and positive Y up.
  39. % The drawing units can be selected (initially inches).  In addition, two
  40. % scaling parameters - unit scale and segment scale - are available.  Their
  41. % effect is multiplicative.
  42.  
  43. % Segments allow for relocatable drawing units.  Inside each segment the
  44. % coordinates are relative to the initial point, which becomes (0 0).
  45. % Scaling is local to segments.  Each segment inherits the unit scale
  46. % scaling outside, but any changes apply to that segment and inferior
  47. % segments.  The segment scale factor is reset to unity on entry to
  48. % each segment.
  49.  
  50. % The coordinates given as command arguments are used to determine
  51. % the size of the drawing.  The size is returned in the TeX dimensions
  52. % \hdrawsize and \vdrawsize.  The width of the plot line, sizes of
  53. % arrowheads, arcs or text do not affect the size of the drawing.
  54.  
  55. % This version writes PostScript commands to an intermediate file.  After
  56. % the drawing is finished, the PostScript file is included in the document
  57. % as a \special include file.
  58.  
  59. % This version has been tested with dvips, version 5.490 (T. Rokicki).
  60.  
  61. %  This file is divided into 4 parts,
  62. %  - TeXdraw user interface
  63. %  - Utility definitions
  64. %  - Low level definitions
  65. %  - PostScript file macros
  66.  
  67.  
  68. \chardef\catamp=\the\catcode`\@
  69. \catcode`\@=11
  70.  
  71. % ===============================================================
  72. % ===== TeXdraw user interface ==================================
  73. \long                              % \centertexdraw needs to be very \long
  74. \def\centertexdraw #1{\hbox to \hsize{\hss
  75.                                       \btexdraw #1\etexdraw
  76.                                       \hss}}
  77.  
  78. % ====== Begin TeXdraw
  79. % Inside the texdraw box:
  80. %   The \vbox should be of zero size, none of the TeXdraw commands generate
  81. %   text; the TeXdraw text commands generate zero size boxes.
  82.  
  83. \def\btexdraw {\x@pix=0             \y@pix=0
  84.                \x@segoffpix=\x@pix  \y@segoffpix=\y@pix
  85. % Set the default values (define outside of the group so that \etexdraw can
  86. % see the scaling parameters)
  87.                \t@exdrawdef
  88.                \setbox\t@xdbox=\vbox\bgroup\offinterlineskip
  89.                    \global\d@bs=0           % pending segments
  90.                    \t@extonlytrue           % no PS commands yet
  91.                    \p@osinitfalse
  92.                    \s@avemove \x@pix \y@pix % capture the initial position
  93.                    \m@pendingfalse
  94.                    \p@osinitfalse           % capture the next move
  95.                    \p@athfalse}
  96.  
  97. % ====== End TeXdraw
  98. % Write out a trailer, close the file, bring in the PostScript code as
  99. % a special include file.  The \special is offset to position on the page
  100. % to be (llx,ury) in PostScript coordinates.
  101.  
  102. % The drawing is placed in a \vbox of size \hdrawsize by \vdrawsize (zero
  103. % depth).  The temporary PostScript file is superimposed with offsets such
  104. % that the lower lefthand corner of the drawing aligns with the lower
  105. % lefthand of the box.  Then, the position is temporarily offset to that
  106. % corresponding to (0 0) to place the TeX text.  Note TeX text goes on top
  107. % of PostScript, to allow for writing on top of filled areas.
  108. \def\etexdraw {\ift@extonly \else
  109.                  \t@drclose      % close the PostScript file
  110.                \fi
  111.                \egroup           % ends vbox \bgroup
  112.                \ifdim \wd\t@xdbox>0pt
  113.                  \errmessage{TeXdraw box non-zero size,
  114.                              possible extraneous text}%
  115.                \fi
  116.                \maxhvpos         % outside group, \hdrawsize \vdrawsize
  117.                \pixtodim \xminpix \l@lxpos  \pixtodim \yminpix \l@lypos
  118.                \vbox {\vskip \vdrawsize
  119.                       \t@xdinclude              % TeXdraw graphics
  120.                       \vskip \l@lypos
  121.                       \hbox {\hskip -\l@lxpos
  122.                              \box\t@xdbox       % TeX text
  123.                              \hskip \hdrawsize
  124.                              \hskip \l@lxpos}%
  125.                       \vskip -\l@lypos\relax}}
  126.  
  127. % ===== Drawing scaling
  128. % The units in any segment may be scaled arbitrarily.  A unit scale is local
  129. % to a segment but affects enclosed segments unless specifically overridden 
  130. % in that segment.  In addition there is a segment scale.  The overall scale
  131. % is the product of the two scaling factors.
  132. %
  133. % Scaling is handled entirely on the TeX side, the PostScript side gets
  134. % absolute pixel coordinates.
  135.  
  136. % Drawing units, e.g. "in" or "cm"
  137. \def\drawdim #1 {\def\d@dim{#1\relax}}
  138.  
  139. % \u@nitsc - unit scale
  140. % \s@egsc  - segment scale
  141. % \d@sc    - drawing scale, product of the unit scale and segment scale
  142.  
  143. % Note that successive application of relative scale factors can lead to
  144. % poor accuracy of the final scale factor.  Each scale factor is represented
  145. % to about 5 decimal digits after the decimal point.
  146. \def\setunitscale #1 {\edef\u@nitsc{#1}%
  147.                       \realmult \u@nitsc  \s@egsc \d@sc}
  148. \def\relunitscale #1 {\realmult {#1}\u@nitsc \u@nitsc
  149.                       \realmult \u@nitsc \s@egsc \d@sc}
  150. \def\setsegscale #1 {\edef\s@egsc {#1}%
  151.                      \realmult \u@nitsc \s@egsc \d@sc}
  152. \def\relsegscale #1 {\realmult {#1}\s@egsc \s@egsc
  153.                      \realmult \u@nitsc \s@egsc \d@sc}
  154.  
  155. % ===== Drawing segments
  156. % The position is restored after a segment.
  157. % Segments use TeX grouping on the TeX side and gsave/grestore on the
  158. % PostScript side to keep changes local.  On the TeX side segments have
  159. % (0 0) as the initial point, while the PostScript side sees no scale
  160. % changes or translations.
  161. \def\bsegment {\ifp@ath
  162.                  \f@lushbs
  163.                  \f@lushmove
  164.                \fi
  165.                \begingroup
  166.                \x@segoffpix=\x@pix
  167.                \y@segoffpix=\y@pix
  168.                \setsegscale 1
  169.                \global\advance \d@bs by 1\relax}
  170. \def\esegment {\endgroup
  171.                \ifnum \d@bs=0
  172.                  \writetx {es}%
  173.                \else
  174.                  \global\advance \d@bs by -1
  175.                \fi}
  176.  
  177. % Save a position
  178. % Save each coordinate as the macro "*name".  The macro is defined to
  179. % be the pixel coordinate value.
  180. \def\savecurrpos (#1 #2){\getsympos (#1 #2)\a@rgx\a@rgy
  181.                          \s@etcsn \a@rgx {\the\x@pix}%
  182.                          \s@etcsn \a@rgy {\the\y@pix}}%
  183. \def\savepos (#1 #2)(#3 #4){\getpos (#1 #2)\a@rgx\a@rgy
  184.                             \coordtopix \a@rgx \t@pixa
  185.                             \advance \t@pixa by \x@segoffpix
  186.                             \coordtopix \a@rgy \t@pixb
  187.                             \advance \t@pixb by \y@segoffpix
  188.                             \getsympos (#3 #4)\a@rgx\a@rgy
  189.                             \s@etcsn \a@rgx {\the\t@pixa}%
  190.                             \s@etcsn \a@rgy {\the\t@pixb}}
  191.  
  192. % ===== Line parameters
  193. % The following parameters apply to subsequent lines.  Each of these
  194. % commands invokes a stroke to draw the previous line segments,
  195. % establishes the current point and then changes the line parameter.
  196. % The parameters are kept local by the PostScript gsave/grestore
  197. % mechanism.  We use \writetx here, instead of \writeps, since we
  198. % do not want to flush any moves.
  199. \def\linewd #1 {\coordtopix {#1}\t@pixa
  200.                 \f@lushbs
  201.                 \writetx {\the\t@pixa\space sl}}
  202. \def\setgray #1 {\f@lushbs
  203.                  \writetx {#1 sg}}
  204. \def\lpatt (#1){\listtopix (#1)\p@ixlist
  205.                 \f@lushbs
  206.                 \writetx {[\p@ixlist] sd}}
  207.  
  208. % ===== Line drawing
  209. % PostScript uses the concept of a path consisting of line segments.
  210. % In this interface to PostScript, paths are continuous across the
  211. % beginning of segments.  Paths terminate at the end of a segment with
  212. % an implicit move.  In addition, paths are both terminated and started
  213. % with a move.  There is a current point at all times, starting with
  214. % initial position (0,0).
  215. \def\lvec (#1 #2){\getpos (#1 #2)\a@rgx\a@rgy
  216.                   \s@etpospix \a@rgx \a@rgy
  217.                   \writeps {\the\x@pix\space \the\y@pix\space lv}}
  218. \def\rlvec (#1 #2){\getpos (#1 #2)\a@rgx\a@rgy
  219.                    \r@elpospix \a@rgx \a@rgy
  220.                    \writeps {\the\x@pix\space \the\y@pix\space lv}}
  221. \def\move (#1 #2){\getpos (#1 #2)\a@rgx\a@rgy
  222.                   \s@etpospix \a@rgx \a@rgy
  223.                   \s@avemove \x@pix \y@pix}
  224. \def\rmove (#1 #2){\getpos (#1 #2)\a@rgx\a@rgy
  225.                    \r@elpospix \a@rgx \a@rgy
  226.                    \s@avemove \x@pix \y@pix}
  227.  
  228. % ===== Circles, ellipses and arcs
  229. % Note that arcs do not update the size of the drawing.
  230. % \lcir, stroked circle
  231. %   r:#1 -  radius
  232. % \fcir, filled circle
  233. %   f:#1 - fill gray level, 0 is black, 1 is white
  234. %   r:#2 - radius
  235. % \ellip, stroked ellipse
  236. %   rx:#1 - x radius
  237. %   ry:#2 - y radius
  238. % \larc, stroked counterclockwise arc, with the present position being
  239. %        the center of the arc.  Only the arc is drawn (not the line
  240. %        joining the center to the beginning of the arc)
  241. %   r:#1  - radius
  242. %   sd:#2 - start angle (degrees)
  243. %   ed:#3 - end angle (degrees)
  244. \def\lcir r:#1 {\coordtopix {#1}\t@pixa
  245.                 \writeps {\the\t@pixa\space cr}%
  246.                 \r@elupd \t@pixa \t@pixa
  247.                 \r@elupd {-\t@pixa}{-\t@pixa}}
  248. \def\fcir f:#1 r:#2 {\coordtopix {#2}\t@pixa
  249.                      \writeps {#1 \the\t@pixa\space fc}%
  250.                      \r@elupd \t@pixa \t@pixa
  251.                      \r@elupd {-\t@pixa}{-\t@pixa}}
  252. \def\lellip rx:#1 ry:#2 {\coordtopix {#1}\t@pixa
  253.                          \coordtopix {#2}\t@pixb
  254.                          \writeps {\the\t@pixa\space \the\t@pixb\space el}%
  255.                          \r@elupd \t@pixa \t@pixb
  256.                          \r@elupd {-\t@pixa}{-\t@pixb}}
  257. \def\larc r:#1 sd:#2 ed:#3 {\coordtopix {#1}\t@pixa
  258.                             \writeps {\the\t@pixa\space #2 #3 ar}}
  259.  
  260. % ===== Fill commands
  261. % The form here completes a path with a closepath, applies the fill,
  262. % starts a newpath and moves to the current point.  The gray level has
  263. % 0 as black and 1 as white.  The current path is terminated.
  264.  
  265. \def\ifill f:#1 {\writeps {#1 fl}}     % Fill only
  266. \def\lfill f:#1 {\writeps {#1 fp}}     % Stroke and fill
  267.  
  268. % ===== Text
  269. % TeX text superimposed on the drawing
  270. %  \htext (x y){text} or \htext {text}
  271. %  \vtext (x y){text} or \vtext {text}
  272. %  \rtext td:angle (x y){text} or \rtext td:angle {text}
  273. %  \textref h:#1 v:#2
  274.  
  275. % The TeX text (or whatever) is placed in an \hbox.  The box is rotated
  276. % for vertical text.  The text is placed on the drawing at the specified
  277. % location (coordinates specified) or the current location (coordinates
  278. % not specified).  The text reference point is placed at that location.
  279. % For the purposes of determining the drawing size, the text box is of
  280. % zero size.
  281.  
  282. % Horizontal text
  283. % Check if the argument starts with a left parenthesis
  284. \def\htext #1{\def\testit {#1}%
  285.               \ifx \testit\l@paren
  286.                 \let\next=\h@move
  287.               \else
  288.                 \let\next=\h@text
  289.               \fi
  290.               \next {#1}}
  291.  
  292. % Rotated text
  293. \def\rtext td:#1 #2{\def\testit {#2}%
  294.                     \ifx \testit\l@paren
  295.                       \let\next=\r@move
  296.                     \else
  297.                       \let\next=\r@text
  298.                     \fi
  299.                     \next td:#1 {#2}}
  300.  
  301. % Vertical text
  302. \def\vtext {\rtext td:90 }
  303.  
  304. % Text reference point
  305. %  h:#1  text horizontal reference point - L, C or R
  306. %  v:#2  text vertical reference point - T, C or B
  307. \def\textref h:#1 v:#2 {\ifx #1R%
  308.                           \edef\l@stuff {\hss}\edef\r@stuff {}%
  309.                         \else
  310.                           \ifx #1C%
  311.                             \edef\l@stuff {\hss}\edef\r@stuff {\hss}%
  312.                           \else  % default L
  313.                             \edef\l@stuff {}\edef\r@stuff {\hss}%
  314.                           \fi
  315.                         \fi
  316.                         \ifx #2T%
  317.                           \edef\t@stuff {}\edef\b@stuff {\vss}%
  318.                         \else
  319.                           \ifx #2C%
  320.                             \edef\t@stuff {\vss}\edef\b@stuff {\vss}%
  321.                           \else  % default B
  322.                             \edef\t@stuff {\vss}\edef\b@stuff {}%
  323.                           \fi
  324.                         \fi}
  325.  
  326. % ===== Arrow vectors
  327. \def\avec (#1 #2){\getpos (#1 #2)\a@rgx\a@rgy
  328.                   \s@etpospix \a@rgx \a@rgy
  329.                   \writeps {\the\x@pix\space \the\y@pix\space (\a@type)
  330.                             \the\a@lenpix\space \the\a@widpix\space av}}
  331.  
  332. \def\ravec (#1 #2){\getpos (#1 #2)\a@rgx\a@rgy
  333.                    \r@elpospix \a@rgx \a@rgy
  334.                    \writeps {\the\x@pix\space \the\y@pix\space (\a@type)
  335.                              \the\a@lenpix\space \the\a@widpix\space av}}
  336.  
  337. % Arrowhead size
  338. %  l:#1 - length of the arrowhead
  339. %  w:#2 - width of the base of the arrowhead
  340. \def\arrowheadsize l:#1 w:#2 {\coordtopix{#1}\a@lenpix
  341.                               \coordtopix{#2}\a@widpix}
  342. % Arrowhead type
  343. %  t:#1 - arrowhead type, F  filled triangle (using current gray level)
  344. %                         T  empty closed triangle
  345. %                         W  white filled triangle
  346. %                         V  Vee shape, at the end of the vector
  347. %                         H  (or other character) Vee shape, vector stops
  348. %                            short of the Vee
  349. \def\arrowheadtype t:#1 {\edef\a@type{#1}}
  350.  
  351. % ===== Bezier curve
  352. % The initial point is assumed to be the current point.  Only the last
  353. % coordinate affects the size of the plot.
  354. \def\clvec (#1 #2)(#3 #4)(#5 #6)%
  355.            {\getpos (#1 #2)\a@rgx\a@rgy
  356.             \coordtopix \a@rgx\t@pixa
  357.             \advance \t@pixa by \x@segoffpix
  358.             \coordtopix \a@rgy\t@pixb
  359.             \advance \t@pixb by \y@segoffpix
  360.             \getpos (#3 #4)\a@rgx\a@rgy
  361.             \coordtopix \a@rgx\t@pixc
  362.             \advance \t@pixc by \x@segoffpix
  363.             \coordtopix \a@rgy\t@pixd
  364.             \advance \t@pixd by \y@segoffpix
  365.             \getpos (#5 #6)\a@rgx\a@rgy
  366.             \s@etpospix \a@rgx \a@rgy
  367.             \writeps {\the\t@pixa\space \the\t@pixb\space 
  368.                       \the\t@pixc\space \the\t@pixd\space 
  369.                       \the\x@pix\space \the\y@pix\space cv}}
  370.  
  371. % ===== Draw the bounding box
  372. \def\drawbb {\bsegment
  373.                \drawdim bp
  374.                \setunitscale 0.24
  375.                \linewd 1           % line width 1/300 inch = 0.24 bp
  376.                \writeps {\the\xminpix\space \the\yminpix\space mv}%
  377.                \writeps {\the\xminpix\space \the\ymaxpix\space lv}%
  378.                \writeps {\the\xmaxpix\space \the\ymaxpix\space lv}%
  379.                \writeps {\the\xmaxpix\space \the\yminpix\space lv}%
  380.                \writeps {\the\xminpix\space \the\yminpix\space lv}%
  381.              \esegment}
  382.  
  383.  
  384. % ===============================================================
  385. % ===== Utility macros used by TeXdraw ==========================
  386.  
  387. % ===== Decode coordinates
  388. % Get coordinates
  389. % This macro is used to get two arguments separated by a blank, with
  390. % possible leading and trailing blanks.  Symbolic coordinates are
  391. % converted to user coordinates.
  392. %  (#1 #2) - coordinates
  393. %  #3 - macro name to receive the x-coordinate value
  394. %  #4 - macro name to receive the y-coordinate value
  395. \def\getpos (#1 #2)#3#4{\g@etargxy #1 #2 {} \\#3#4%
  396.                         \c@heckast #3%
  397.                         \ifa@st
  398.                           \g@etsympix #3\t@pixa
  399.                           \advance \t@pixa by -\x@segoffpix
  400.                           \pixtocoord \t@pixa #3%
  401.                         \fi
  402.                         \c@heckast #4%
  403.                         \ifa@st
  404.                           \g@etsympix #4\t@pixa
  405.                           \advance \t@pixa by -\y@segoffpix
  406.                           \pixtocoord \t@pixa #4%
  407.                         \fi}
  408.  
  409. % Get symbolic coordinate names
  410. %  (#1 #2) - symbolic coordinates
  411. %  #3 - macro name to receive the symbolic x coordinate name
  412. %  #4 - macro name to receive the symbolic y coordinate name
  413. \def\getsympos (#1 #2)#3#4{\g@etargxy #1 #2 {} \\#3#4%
  414.                            \c@heckast #3%
  415.                            \ifa@st \else
  416.                              \errmessage {TeXdraw: invalid symbolic coordinate}
  417.                            \fi
  418.                            \c@heckast #4%
  419.                            \ifa@st \else
  420.                              \errmessage {TeXdraw: invalid symbolic coordinate}
  421.                            \fi}
  422.  
  423. % ===== Convert a list of values to pixel values
  424. %  (#1) - blank separated list of values in user coordinates
  425. %  #2 - macro name to receive the blank separated list of pixel values
  426. \def\listtopix (#1)#2{\def #2{}
  427.                       \edef\l@ist {#1 }%    % append a blank to the string
  428.                       \t@counta=0
  429.                       \loop
  430.                         \expandafter\g@etitem \l@ist \\\a@rgx\l@ist
  431.                         \a@pppix \a@rgx #2%
  432.                         \ifx \l@ist\empty
  433.                           \t@counta=1
  434.                         \fi
  435.                       \ifnum \t@counta=0
  436.                       \repeat}
  437.  
  438. % ===== Real multiplication
  439. % This function uses the property that a box dimension may be scaled by
  440. % a real value.  The values are converted to dimensions in units of pt.
  441. % This choice gives us a reasonable dynamic range.  The final step is to
  442. % clean off the "pt" on the resulting dimension.  Note that these are fixed
  443. % point operations with each operand represented to an accuracy of about 5
  444. % decimal places.
  445.  
  446. % Note we must use magnified points not "true" points, since the answer is
  447. % expressed in magnified points.  The result will be calculated in the same
  448. % manner no matter what the magnification is.
  449. %  #1 and #2 are multiplicands
  450. %  #3 macro name to capture the real result
  451. \def\realmult #1#2#3{\dimen0=#1pt
  452.                      \dimen2=#2\dimen0
  453.                      \edef #3{\expandafter\c@lean\the\dimen2}}
  454.  
  455. % ===== Divide integers, real result
  456. %  #1 integer numerator value
  457. %  #2 integer denominator (divisor) value
  458. %  #3 macro name to capture the real result
  459. \def\intdiv #1#2#3{\t@counta=#1
  460.                    \t@countb=#2
  461. %  Limitations: #1 must be negatable, i.e. it must not be the largest
  462. %                  magnitude negative number
  463. %               #2 must be able to be multiplied by 2 without overflow
  464. %  Calculate a*65536/b  where the factor 65536 converts from pt to sp.
  465. %  This operation can also be interpretated as an extended precision
  466. %  numerator divided by the denominator.  The scheme used is basically a
  467. %  long division, except that it is bootstrapped by an integer divide.
  468. %  The computations are carried out with positive numerator and denominator,
  469. %  with the appropriate correction at the end.
  470. %    \t@counta == remainder, r, initially set to a
  471. %    \t@countb == denominator, b
  472. %    \t@countc == quotient, q
  473. %    \t@countd == +1, a and b have the same sign
  474. %                 -1, a and b have opposite signs
  475. %    \t@counte == temporary register and loop counter
  476.                \ifnum \t@countb<0
  477.                       \t@counta=-\t@counta
  478.                       \t@countb=-\t@countb
  479.                    \fi
  480.                    \t@countd=1                    % record the sign
  481.                    \ifnum \t@counta<0
  482.                       \t@counta=-\t@counta
  483.                       \t@countd=-1
  484.                    \fi
  485. %                                                 % q=a/b, r=a-q/b
  486.                \t@countc=\t@counta  \divide \t@countc by \t@countb
  487.                    \t@counte=\t@countc  \multiply \t@counte by \t@countb
  488.                    \advance \t@counta by -\t@counte
  489.                \t@counte=-1
  490.                    \loop
  491.                      \advance \t@counte by 1
  492.                  \ifnum \t@counte<16
  493.                        \multiply \t@countc by 2           % q=2q
  494.                        \multiply \t@counta by 2           % r=2r
  495.                        \ifnum \t@counta<\t@countb \else   % if ( r >= b )
  496.                          \advance \t@countc by 1          %   q=q+1
  497.                          \advance \t@counta by -\t@countb %   r=r-b
  498.                        \fi
  499.                    \repeat
  500.                \divide \t@countb by 2         % rounding
  501.                \ifnum \t@counta<\t@countb     % if ( r >= b/2 ) q=q+1
  502.                      \advance \t@countc by 1
  503.                    \fi
  504.                    \ifnum \t@countd<0             % fix up the sign of output
  505.                      \t@countc=-\t@countc
  506.                    \fi
  507.                    \dimen0=\t@countc sp           % express as a dimension
  508.                    \edef #3{\expandafter\c@lean\the\dimen0}}
  509.  
  510. % ===== Global version of \newif
  511. % Plain TeX defines the \newif such that \xxxtrue sets the flag locally.
  512. % We need a similar construction but with \xxxtrue and \xxxfalse setting
  513. % the flag globally so that it can reach outside of a group (segment).
  514. % (see Appendix B, TeXBook)
  515. % \gnewif\iffoo creates \footrue, \foofalse to go with \iffoo.
  516. \outer\def\gnewif #1{\count@\escapechar \escapechar\m@ne
  517.   \expandafter\expandafter\expandafter
  518.    \edef\@if #1{true}{\global\let\noexpand#1=\noexpand\iftrue}%
  519.   \expandafter\expandafter\expandafter
  520.    \edef\@if #1{false}{\global\let\noexpand#1=\noexpand\iffalse}%
  521.   \@if#1{false}\escapechar\count@} % the condition starts out false
  522. \def\@if #1#2{\csname\expandafter\if@\string#1#2\endcsname}
  523. {\uccode`1=`i \uccode`2=`f \uppercase{\gdef\if@12{}}} % `if' is required
  524.  
  525.  
  526. % ===============================================================
  527. % ===== Internal TeXdraw macros =================================
  528.  
  529. % ===== Macros for converting between dimensions and units
  530. % Convert drawing units (coordinate value, scaled by the unit scale and
  531. % segment scale) to pixels.  We use rounding to get more accurate results.
  532. %  #1 dimension in drawing units
  533. %  #2 count in pixels (returned into a count)
  534. \def\coordtopix #1#2{\dimen0=#1\d@dim
  535.                      \dimen2=\d@sc\dimen0
  536.                      \t@counta=\dimen2              % scaled dimension in sp
  537.                      \t@countb=\s@ppix
  538.                      \divide \t@countb by 2
  539.                      \ifnum \t@counta<0             % rounding
  540.                        \advance \t@counta by -\t@countb
  541.                      \else
  542.                        \advance \t@counta by \t@countb
  543.                      \fi
  544.                      \divide \t@counta by \s@ppix
  545.                      #2=\t@counta}
  546.  
  547. % Convert from absolute pixels to relative scaled coordinates
  548. %  #1 - input integer pixel value
  549. %  #2 - macro name to receive the character string corresponding to the
  550. %       floating point coordinate value
  551. \def\pixtocoord #1#2{\t@counta=#1%
  552.                      \multiply \t@counta by \s@ppix
  553.                      \dimen0=\d@sc\d@dim
  554.                      \t@countb=\dimen0
  555.                      \intdiv \t@counta \t@countb #2}
  556.  
  557. % Convert pixels to TeX dimensions.
  558. %  #1 - input integer pixel value
  559. %  #2 - returned dimension (returned into a dimension register)
  560. \def\pixtodim #1#2{\t@countb=#1%
  561.                    \multiply \t@countb by \s@ppix
  562.                    #2=\t@countb sp\relax}
  563.  
  564. % Convert pixels to (integer) bp units
  565. %  #1 - input pixel value
  566. %  #2 - integer value, returned into a count
  567. \def\pixtobp #1#2{\dimen0=\p@sfactor pt
  568.                   \t@counta=\dimen0
  569.                   \multiply \t@counta by #1%
  570.                   \ifnum \t@counta < 0             % rounding
  571.                     \advance \t@counta by -32768
  572.                   \else
  573.                     \advance \t@counta by 32768
  574.                   \fi
  575.                   \divide \t@counta by 65536
  576.                   #2=\t@counta}
  577.                   
  578. % ===== Allocations for registers and counts
  579. % == Temporary count registers
  580. % NB: We try to economize on the use of temporary counts and dimensions.
  581. %     Several counts and dimenstions are in fact equivalent, with only the
  582. %     name being changed to be more meaningful.
  583. \newcount\t@counta    \newcount\t@countb   % Use at lowest levels
  584. \newcount\t@countc    \newcount\t@countd
  585. \newcount\t@counte
  586. \newcount\t@pixa      \newcount\t@pixb     % Use for pixel values
  587. \newcount\t@pixc      \newcount\t@pixd
  588. \let\l@lxbp=\t@pixa   \let\l@lybp=\t@pixb  % Use for (integer) bp values
  589. \let\u@rxbp=\t@pixc   \let\u@rybp=\t@pixd
  590.  
  591. % == Temporary dimension registers
  592. \newdimen\t@xpos      \newdimen\t@ypos
  593. \let\l@lxpos=\t@xpos  \let\l@lypos=\t@ypos
  594.  
  595. % == Position and parameter registers
  596. % The minimum and maximum extent in the X and Y direction in pixel units
  597. % (updated globally to reach outside segments)
  598. \newcount\xminpix      \newcount\xmaxpix
  599. \newcount\yminpix      \newcount\ymaxpix
  600.  
  601. % == Arrowhead parameters
  602. \newcount\a@lenpix     \newcount\a@widpix
  603.  
  604. % == Absolute pixel position
  605. \newcount\x@pix        \newcount\y@pix
  606. \newcount\x@segoffpix  \newcount\y@segoffpix
  607. \newcount\x@savepix    \newcount\y@savepix
  608.  
  609. % == Conversion factor
  610. \newcount\s@ppix       % sp/pixel 
  611.  
  612. % == Pending segments count
  613. \newcount\d@bs
  614.  
  615. % == Counter to form unique file names
  616. \newcount\t@xdnum
  617. \global\t@xdnum=0
  618.  
  619. % == Drawing size in TeX dimensions
  620. \newdimen\hdrawsize    \newdimen\vdrawsize
  621.  
  622. % == TeXdraw box
  623. \newbox\t@xdbox
  624.  
  625. % == Output stream number for the PostScript file
  626. \newwrite\drawfile
  627.  
  628. % == \newif and \gnewif
  629. \newif\ifm@pending
  630. \newif\ifp@ath
  631. \newif\ifa@st
  632. \gnewif \ift@extonly
  633. \gnewif\ifp@osinit
  634.  
  635. % ===== Character definitions
  636. \def\l@paren{(}
  637. \def\a@st{*}
  638.  
  639. % ===== Special character macros
  640. % Need to be able to insert "%", "{" and "}" characters into the
  641. % PostScript file.
  642. % Define macros which have these characters with category "other".
  643. % We will assume, that these characters have the standard meanings --
  644. % after all, we use comments and braces in this code.
  645. \catcode`\%=12
  646.   \def\p@b {%!}  \def\p@p {%%}
  647. \catcode`\%=14
  648. \catcode`\{=12  \catcode`\}=12  \catcode`\u=1 \catcode`\v=2
  649.   \def\l@br u{v  \def\r@br u}v
  650. \catcode `\{=1  \catcode`\}=2   \catcode`\u=11 \catcode`\v=11
  651.  
  652. % ===== Pixel conversion factors
  653. % The position is kept as an integer value (count).  It is set to a resolution
  654. % corresponding to 300 units/inch.  We refer to them as pixels, but in fact
  655. % the resolution is just that: movements are quantized to lie on a grid with
  656. % that resolution.
  657.  
  658. % Using pixel units which correspond to the actual resolution of the device
  659. % has advantages in that all horizontal and vertical lines then will be
  660. % drawn with the same line thickness.  In addition the coordinates are
  661. % then integer values (no decimal point or leading zeros) which leads
  662. % to a more compact PostScript file.
  663.  
  664. % The following macro sets the conversion from PostScript units (bp) to the
  665. % integer units (pixels).  The file inclusion \special environment in the
  666. % PostScript driver restores the context to default PostScript values
  667. % (bp or 72/in and origin in the lower lefthand corner).  A scaling value
  668. % of 0.24 converts to 300/inch.  Note that the PostScript commands written
  669. % to the temporary PostScript file do not depend on the TeX magnification
  670. % in effect.  Magnification will be handled by the dvi to PostScript driver
  671. % at the time that the file is included in the output.
  672.  
  673. % Calculate the conversion factors
  674. % Let sppix = sp/pixel = u / p, where u = sp/unit and p = pix/unit (both
  675. % integer values).
  676. % We calculate sppix as
  677. %         s@ppix = [ (u+0.5p)/p ]
  678. % We also calculate the PostScript scale factor bp/pixel
  679. % Let b = sp/bp.  We want p@sfactor = s@ppix/b.  For 300 pixels/inch, this
  680. % gives p@sfactor=0.24.  Using rounding
  681. %         p@sfactor = [ (s@ppix+0.5b)/b ] .
  682. % To carry out the arithmetic, we will operate in sp units (integers) and
  683. % generate the answer in pt units (multiplying by sp/pt).  This result will
  684. % expressed as a character string representing a real number after the "pt"
  685. % designator is stripped off.
  686.  
  687. {\catcode`\p=12 \catcode`\t=12
  688.  \gdef\c@lean #1pt{#1}}
  689.  
  690. \def\sppix#1/#2 {\dimen0=1#2 \s@ppix=\dimen0
  691.                  \t@counta=#1%
  692.                  \divide \t@counta by 2
  693.                  \advance \s@ppix by \t@counta
  694.                  \divide \s@ppix by #1%             % \s@ppix available
  695.                  \t@counta=\s@ppix
  696.                  \multiply \t@counta by 65536       % 1 pt = 65536 sp
  697.                  \advance \t@counta by 32891        % 0.5 bp = 32890.88 sp
  698.                  \divide \t@counta by 65782         % 1 bp = 65781.76 sp
  699.                  \dimen0=\t@counta sp
  700.                  \edef\p@sfactor {\expandafter\c@lean\the\dimen0}}
  701.  
  702. % ===== Low level coordinate decoding macros
  703. % Get two values, separated by a blank
  704. % Invoke as \g@etargxy <stuff> {} \\\ma\mb
  705. \def\g@etargxy #1 #2 #3 #4\\#5#6{\def #5{#1}%
  706.                                  \ifx #5\empty
  707.                                    \g@etargxy #2 #3 #4 \\#5#6%  leading blank
  708.                                  \else
  709.                                    \def #6{#2}%
  710.                                    \def\next {#3}%
  711.                                    \ifx \next\empty \else
  712.                                      \errmessage {TeXdraw: invalid coordinate}%
  713.                                    \fi
  714.                                  \fi}
  715.  
  716. % Check for a leading asterisk
  717. % Sets \a@stfalse or \a@sttrue, test with \ifa@st
  718. \def\c@heckast #1{\expandafter
  719.                   \c@heckastll #1\\}
  720. \def\c@heckastll #1#2\\{\def\testit {#1}%
  721.                         \ifx \testit\a@st
  722.                           \a@sttrue
  723.                         \else
  724.                           \a@stfalse
  725.                         \fi}
  726.  
  727. % Decode a symbolic coordinate
  728. % Pixel value returned to a count
  729. \def\g@etsympix #1#2{\expandafter
  730.                      \ifx \csname #1\endcsname \relax
  731.                        \errmessage {TeXdraw: undefined symbolic coordinate}%
  732.                      \fi
  733.                      #2=\csname #1\endcsname}
  734.  
  735. % Set a macro named #1 to have value #2
  736. \def\s@etcsn #1#2{\expandafter
  737.                   \xdef\csname#1\endcsname {#2}}
  738.  
  739. % ===== Low level list decoding macros
  740. % Pick off the first item -> #3, rest of string -> #4
  741. \def\g@etitem #1 #2\\#3#4{\edef #4{#2}\edef #3{#1}}
  742. \def\a@pppix #1#2{\edef\next {#1}%
  743.                   \ifx \next\empty \else
  744.                     \coordtopix {#1}\t@pixa
  745.                     \ifx #2\empty
  746.                       \edef #2{\the\t@pixa}%
  747.                     \else
  748.                       \edef #2{#2 \the\t@pixa}%
  749.                     \fi
  750.                   \fi}
  751.  
  752. % ===== Macros for updating the position
  753. % Calculate the position in pixels and update the maximum excursions
  754. \def\s@etpospix #1#2{\coordtopix {#1}\x@pix
  755.                      \advance \x@pix by \x@segoffpix
  756.                      \coordtopix {#2}\y@pix
  757.                      \advance \y@pix by \y@segoffpix
  758.                      \u@pdateminmax \x@pix \y@pix}
  759.  
  760. \def\r@elpospix #1#2{\coordtopix {#1}\t@pixa
  761.                      \advance \x@pix by \t@pixa
  762.                      \coordtopix {#2}\t@pixa
  763.                      \advance \y@pix by \t@pixa
  764.                      \u@pdateminmax \x@pix \y@pix}
  765.  
  766. \def\r@elupd #1#2{\t@counta=\x@pix
  767.                   \advance\t@counta by #1%
  768.                   \t@countb=\y@pix
  769.                   \advance\t@countb by #2%
  770.                   \u@pdateminmax \t@counta \t@countb}
  771.  
  772. \def\u@pdateminmax #1#2{\ifnum #1>\xmaxpix
  773.                           \global\xmaxpix=#1%
  774.                         \fi
  775.                         \ifnum #1<\xminpix
  776.                           \global\xminpix=#1%
  777.                         \fi
  778.                         \ifnum #2>\ymaxpix
  779.                           \global\ymaxpix=#2%
  780.                         \fi
  781.                         \ifnum #2<\yminpix
  782.                           \global\yminpix=#2%
  783.                         \fi}
  784.  
  785. % Convert maximum excursions in pixel units to TeX dimensions
  786. % (\xminpix \yminpix) <-> (\xmaxpix \ymaxpix)  pixel units
  787. % \hdrawsize, \vdrawsize                     TeX dimensions
  788. \def\maxhvpos {\t@pixa=\xmaxpix
  789.                \advance \t@pixa by -\xminpix
  790.                \pixtodim  \t@pixa {\dimen2}%
  791.                \global\hdrawsize=\dimen2
  792.                \t@pixa=\ymaxpix
  793.                \advance \t@pixa by -\yminpix
  794.                \pixtodim \t@pixa {\dimen2}%
  795.                \global\vdrawsize=\dimen2\relax}
  796.  
  797. % ===== Include the TeXdraw graphics
  798. % The drawing will be placed such that its lower left hand corner will
  799. % be at the current TeX position
  800. \def\t@xdinclude {\pixtobp {-\xminpix}\l@lxbp  \pixtobp {-\yminpix}\l@lybp
  801.                   \ift@extonly \else
  802.                     \special {psfile=\p@sfile\space
  803.                               hoffset=\the\l@lxbp\space
  804.                               voffset=\the\l@lybp}%
  805.                   \fi}
  806.  
  807. % =====  Save moves / flush moves
  808. % A TeXdraw segment which generates only TeX text uses only move, begin
  809. % segment and end segment commands.  The goal is to avoid writing out
  810. % empty segments for such cases.  To this end, moves are held back and
  811. % only written out if necessary to set the position or terminate a path.
  812. % Also in this way, a TeXdraw drawing which generates only TeX text will
  813. % not generate a PostScript file.
  814.  
  815. % Two flags are used.  Both flags are local to a segment.
  816. % - move pending:  Set when a move has been invokded but the move command
  817. %   has not been written out to the PostScript file
  818. % - path in progress:  Set when a PostScript path has been started but the
  819. %   path has not been terminated and stroked.
  820. % (1) Moves are kept back.  Using TeX's groups, a local flag and local
  821. %     position registers are used to keep track of whether the latest
  822. %     move applicable to a given segment has been written out or not.  In
  823. %     effect there is a stack of pending moves, one for each level of
  824. %     segment nesting.
  825. % (2) At the beginning of a segment, if a PS path is in progress and a
  826. %     a move is pending, the move is written out, terminating the path
  827. %     and stroking the path.  This is done to ensure that the path is
  828. %     stroked before lines and/or fills are executed in the segment.
  829. % (3) At the beginning of a segment, if a PS path is not in progress,
  830. %     any pending moves are kept back.  Effectively, the move will be
  831. %     transferred into the segment.  It will be written out only when
  832. %     the position needs to be updated for some other command.  Such
  833. %     moves which are transferred into segments may have to be repeated
  834. %     outside the segment.  The move pending flag will be restored to
  835. %     the value outside the segment on exit from the segment.
  836. % (4) A begin segment command is not written out, but instead a global
  837. %     segment backlog counter is incremented.  The backlog of begin
  838. %     segment commands is written out when a drawing command is encountered.
  839. % These affect the TeXdraw commands as follows.
  840. % (a) move:
  841. %     - set the current position
  842. %     - record the position of the saved move
  843. %     - set the move pending flag
  844. % (b) begin segment:
  845. %     - if a path is in progress
  846. %         - if a move is pending
  847. %           - if there is a backlog of segments
  848. %             - write out enough begin segments to clear the backlog
  849. %           - write out the pending move
  850. %           - reset the move pending flag (local to the containing segment,
  851. %             but affects inferior segments)
  852. %           - reset the path in progress flag
  853. %     - increment the segment backlog counter
  854. %     - begin a group
  855. % (c) end segment:
  856. %     - end a group
  857. %     - if there is no backlog of segments
  858. %       - write an end segment command
  859. %     - if there is a backlog of segments
  860. %       - decrement the backlog counter, thereby omitting an empty
  861. %         empty segment.
  862. %     - the move pending flag and path in progress flag are automatically
  863. %       restored on leaving the TeX group
  864. % (d) text:
  865. %     - create a text box
  866. % (e) line parameters:
  867. %     - if there is a backlog of segments
  868. %        - write out enough begin segments to clear the backlog
  869. %     - clear the path in progress flag
  870. %     - write the PS command changing the line parameter
  871. % (f) other drawing commands:
  872. %     - update the current position
  873. %     - if there is a backlog of segments
  874. %        - write out enough begin segments to clear the backlog
  875. %     - if there is a pending move
  876. %        - write out the pending move
  877. %        - reset the move pending flag (local to this segment, but affects
  878. %          inferior segments)
  879. %     - set the path in progress flag
  880. %     - write the drawing command
  881. % Notes:
  882. % (1) The es PS command strokes the path at the end of a segment to
  883. %     ensure that the correct line parameters are used for the segment.
  884. %     The path before the corresponding bs command is restored and
  885. %     continued.
  886. % (2) The \f@lushbs and \f@lushmove commands must be invoked before each
  887. %     drawing command written to the PS file.  The macro \writeps includes
  888. %     these operations.
  889.  
  890. % Another awkward business has to do with initialization.  We want a default
  891. % (0 0) initial position so that the user can draw vectors immediately.
  892. % However, if the user specifies another move before beginning to draw,
  893. % that position should be the initial position.  The importance of this
  894. % initial position is that the determination of the maximum excursion
  895. % must take this value into account.  We handle the initialization in the
  896. % \s@avemove and \f@lushmove macros.  The macro \ifp@osinit indicates whether
  897. % the next move should be captured as the initial values for \xminpix,
  898. % \yminpix, \xmaxpix, and \ymaxpix.  However, if a \f@lushmove is invoked,
  899. % then we assume that the appropriate initial values has already been set.
  900. % The "mv" command in PostScript is defined to stroke the current path (if
  901. % any) and move to the pixel coordinates specified.
  902.  
  903. % Note that \m@pendingtrue and \m@pendingfalse define the flag locally.
  904. % In addition, \x@savepix and \y@savepix are local variables.  We make
  905. % use of the fact that the values of the flag and positions propagate
  906. % down to inferior segments but not up to superior segments.  This behaviour
  907. % is consistent with the gsave/grestore operation on the PostScript side.
  908. \def\s@avemove #1#2{\x@savepix=#1\y@savepix=#2%
  909.                     \m@pendingtrue
  910.                     \ifp@osinit \else
  911.                       \p@osinittrue
  912.                       \global\xminpix=\x@savepix \global\yminpix=\y@savepix
  913.                       \global\xmaxpix=\x@savepix \global\ymaxpix=\y@savepix
  914.                     \fi}
  915.  
  916. \def\f@lushmove {\p@osinittrue
  917.                  \ifm@pending
  918.                    \writetx {\the\x@savepix\space \the\y@savepix\space mv}%
  919.                    \m@pendingfalse
  920.                    \p@athfalse
  921.                  \fi}
  922.  
  923. % =====  Flush begin segment
  924. % \f@lushbs flushes any saved up \bsegments.  Some of these may be redundant,
  925. % but we cannot know without looking ahead beyond the \esegment.
  926. \def\f@lushbs {\loop
  927.                  \ifnum \d@bs>0
  928.                    \writetx {bs}%
  929.                    \global\advance \d@bs by -1
  930.                \repeat}
  931.                
  932. % ===== Internal text macros
  933. % Horizontal text, use only 3 levels of box nesting here
  934. \def\h@move #1#2 #3)#4{\move (#2 #3)%
  935.                        \h@text {#4}}
  936. \def\h@text #1{\pixtodim \x@pix \t@xpos
  937.                \pixtodim \y@pix \t@ypos
  938.                \vbox to 0pt{\normalbaselines
  939.                             \t@stuff
  940.                             \kern -\t@ypos
  941.                             \hbox to 0pt{\l@stuff
  942.                                          \kern \t@xpos
  943.                                          \hbox {#1}%
  944.                                          \kern -\t@xpos
  945.                                          \r@stuff}%
  946.                             \kern \t@ypos
  947.                             \b@stuff\relax}}
  948.  
  949. % Rotated text
  950. % Uses 5 levels of box nesting here (so that the text reference point
  951. % is that <before> rotation).  This was done so that the reference point
  952. % definition makes sense with arbitrary angle rotation.  The text is
  953. % rotated with respect to the text reference point.  The result is zero
  954. % sized.  This macro generates in-line PostScript.
  955. % #1 - rotation angle in degrees
  956. % #2 - text to be rotated
  957. \def\r@move td:#1 #2#3 #4)#5{\move (#3 #4)%
  958.                              \r@text td:#1 {#5}}
  959. \def\r@text td:#1 #2{\pixtodim \x@pix \t@xpos
  960.                      \pixtodim \y@pix \t@ypos
  961.                      \vbox to 0pt{\kern -\t@ypos
  962.                                   \hbox to 0pt{\kern \t@xpos
  963.                                                \rottxt{#1}{#2}%
  964.                                                \hss}%
  965.                                   \vss}}
  966.  
  967. \def\rottxt #1#2{\special{ps: gsave currentpoint currentpoint translate
  968.                               #1 neg rotate neg exch neg exch translate}%
  969.                  \z@sb{#2}%
  970.                  \special{ps: currentpoint grestore moveto}}
  971. \def\z@sb #1{\vbox to 0pt{\normalbaselines
  972.                           \t@stuff
  973.                           \hbox to 0pt{\l@stuff
  974.                                        \hbox {#1}%
  975.                                        \r@stuff}%
  976.                           \b@stuff}}
  977.  
  978. % ===== Default values
  979. % These are reset each time TeXdraw is invoked
  980. \def\t@exdrawdef {\sppix 300/in            % 300 pixels/inch
  981.                   \drawdim in              % drawing units are inches
  982.                   \edef\u@nitsc {1}%       % unit scale 1 (has to be set before
  983.                                            % we can invoke \setsegscale)
  984.                   \setsegscale 1           % segment scale 1
  985.                   \arrowheadsize l:0.16 w:0.08
  986.                   \arrowheadtype t:T
  987.                   \textref h:L v:B }
  988.  
  989.  
  990. % ===============================================================
  991. % ===== PostScript file macros ==================================
  992.  
  993. % ===== Write to the PostScript file
  994. % Macro to write PostScript commands to the temporary PostScript file
  995. % To decrease the size of the PostScript file, moves are kept back to
  996. % allow redundant multiple moves to be removed.  In addition empty gsave/
  997. % grestore pairs are not written.  The PostScript file is not opened if
  998. % TeXdraw has not generated any PostScript commands, i.e. it has produced
  999. % only TeX text.
  1000. % \writeps : flushes the pending move to make sure things are positioned
  1001. %            correctly and flushes pending begin segments before calling
  1002. %            \writetx to write to the PostScript file
  1003. % \writetx : writes directly to the PostScript file.  This version is used
  1004. %            only for those commands which just change line parameters
  1005. %            without drawing.  This routine opens the file and writes the
  1006. %            PS file header the first time it is called.
  1007. % \w@rps :   lowest level direct write to the PostScript file
  1008. \def\writeps #1{\f@lushbs
  1009.                 \f@lushmove
  1010.                 \p@athtrue
  1011.                 \writetx {#1}}
  1012. \def\writetx #1{\ift@extonly
  1013.                   \t@extonlyfalse
  1014.                   \t@dropen
  1015.                 \fi
  1016.                 \w@rps {#1}}
  1017. \def\w@rps #1{\immediate\write\drawfile {#1}}
  1018.  
  1019. % ===== Open a PostScript file
  1020. % Open the file, write the definitions used by TeXdraw.
  1021. \def\t@dropen {%
  1022.   \global\advance \t@xdnum by 1
  1023.   \ifnum \t@xdnum<10
  1024.     \xdef\p@sfile {\jobname.ps\the\t@xdnum}
  1025.   \else
  1026.     \xdef\p@sfile {\jobname.p\the\t@xdnum}
  1027.   \fi
  1028.   \immediate\openout\drawfile=\p@sfile
  1029.   \w@rps {\p@b PS-Adobe-3.0 EPSF-3.0}%
  1030.   \w@rps {\p@p BoundingBox: (atend)}%
  1031.   \w@rps {\p@p Title: TeXdraw drawing: \p@sfile}%
  1032.   \w@rps {\p@p Pages: 1}%
  1033.   \w@rps {\p@p Creator: \TeXdrawId}%
  1034.   \w@rps {\p@p CreationDate: \the\year/\the\month/\the\day}%
  1035.   \w@rps {50 dict begin}%
  1036.   \w@rps {/mv {stroke moveto} def}%
  1037.   \w@rps {/lv {lineto} def}%
  1038.   \w@rps {/st {currentpoint stroke moveto} def}%
  1039.   \w@rps {/sl {st setlinewidth} def}%
  1040.   \w@rps {/sd {st 0 setdash} def}%
  1041.   \w@rps {/sg {st setgray} def}%
  1042.   \w@rps {/bs {gsave} def /es {stroke grestore} def}%
  1043.   \w@rps {/cv {curveto} def}%
  1044.   \w@rps {/cr \l@br gsave /rad exch def currentpoint newpath rad 0 360 arc}%
  1045.   \w@rps { stroke grestore\r@br\space def}%
  1046.   \w@rps {/fc \l@br gsave /rad exch def setgray currentpoint newpath}%
  1047.   \w@rps { rad 0 360 arc fill grestore\r@br\space def}%
  1048.   \w@rps {/ar {gsave currentpoint newpath 5 2 roll arc stroke grestore} def}%
  1049.   \w@rps {/el \l@br gsave /rady exch def /radx exch def}%
  1050.   \w@rps { /svm matrix currentmatrix def currentpoint translate}%
  1051.   \w@rps { radx rady scale newpath 0 0 1 0 360 arc}%
  1052.   \w@rps { svm setmatrix stroke grestore\r@br\space def}%
  1053.   \w@rps {/fl \l@br gsave closepath setgray fill grestore}%
  1054.   \w@rps { currentpoint newpath moveto\r@br\space def}%
  1055.   \w@rps {/fp \l@br gsave closepath setgray fill grestore}%
  1056.   \w@rps { currentpoint stroke moveto\r@br\space def}%
  1057.   \w@rps {/av \l@br /hhwid exch 2 div def /hlen exch def}%
  1058.   \w@rps { /ah exch def /tipy exch def /tipx exch def}%
  1059.   \w@rps { currentpoint /taily exch def /tailx exch def}%
  1060.   \w@rps { /dx tipx tailx sub def /dy tipy taily sub def}%
  1061.   \w@rps { /alen dx dx mul dy dy mul add sqrt def}%
  1062.   \w@rps { /blen alen hlen sub def}%
  1063.   \w@rps { gsave tailx taily translate dy dx atan rotate}%
  1064.   \w@rps { (V) ah ne {blen 0 gt {blen 0 lineto} if} {alen 0 lineto} ifelse}%
  1065.   \w@rps { stroke blen hhwid neg moveto alen 0 lineto blen hhwid lineto}%
  1066.   \w@rps { (T) ah eq {closepath} if}%
  1067.   \w@rps { (W) ah eq {gsave 1 setgray fill grestore closepath} if}%
  1068.   \w@rps { (F) ah eq {fill} {stroke} ifelse}%
  1069.   \w@rps { grestore tipx tipy moveto\r@br\space def}%
  1070.   \w@rps {\p@sfactor\space \p@sfactor\space scale}%
  1071.   \w@rps {1 setlinecap 1 setlinejoin}%
  1072.   \w@rps {3 setlinewidth [] 0 setdash}%
  1073.   \w@rps {0 0 moveto}%
  1074. }
  1075.  
  1076. % Notes:
  1077. % - mv (move to) This command includes a stroke before the moveto.  The
  1078. %      stroke terminates a path and the move begins another path.
  1079. % - bs (begin segment) encloses a segment in a gsave/grestore to keep
  1080. %      changes to line parameters local.
  1081. % - es (end segment) does a "stroke grestore" to make sure lines inside
  1082. %      the segment use the line parameters local to that segment
  1083. % - ar (arc) The path is generated and stroked inside a gsave/grestore,
  1084. %      leaving the current path intact.
  1085. % - cr (circle) The path is generated and stroked inside a gsave/grestore,
  1086. %      leaving the current path intact.
  1087. % - fc (filled circle) The path is generated and filled inside a gsave/
  1088. %      grestore, keeping the fill level local to the circle.  The current
  1089. %      path is left intact.
  1090. % - el (ellipse) The path is generated and stroked inside a gsave/grestore,
  1091. %      leaving the current path intact.  The elliptical path is defined
  1092. %      with different x and y scaling, then stroked with default scaling
  1093. %      to give a constant line thickness.
  1094. % - fl (fill) The current path is closed and filled inside a gsave/restore,
  1095. %      keeping the fill level local.  A newpath terminates the path.
  1096. % - fp (fill path) The current path is closed and then filled inside a
  1097. %      gsave/grestore.  Finally the closed path is stroked, implicitly
  1098. %      terminating the path.
  1099. % - av (arrow vector) The arrow vector is drawn inside a gsave/grestore.
  1100. %      The line width and type is that currently in effect.  After the
  1101. %      grestore, the current path is continued with a move to the tip of
  1102. %      the vector.
  1103.  
  1104. % ===== Close the PostScript file
  1105. % Write a trailer with the BoundingBox, close the file.  Note that the
  1106. % BoundingBox may be larger than the commands in the PostScript file
  1107. % indicate.  This is due to the fact that multiple move commands in
  1108. % a row are collapsed into a single move.  The BoundingBox information
  1109. % includes the effect of the moves which were expunged.
  1110. \def\t@drclose {%
  1111.   \w@rps {stroke end showpage}%
  1112.   \w@rps {\p@p Trailer:}%
  1113.   \pixtobp \xminpix \l@lxbp  \pixtobp \yminpix \l@lybp
  1114.   \pixtobp \xmaxpix \u@rxbp  \pixtobp \ymaxpix \u@rybp
  1115.   \w@rps {\p@p BoundingBox: \the\l@lxbp\space \the\l@lybp\space
  1116.                             \the\u@rxbp\space \the\u@rybp}%
  1117.   \w@rps {\p@p EOF}%
  1118.   \closeout\drawfile
  1119. }
  1120.  
  1121. % ===============================================================
  1122. \catcode`\@=\catamp
  1123.